﻿// Inner Fire 游戏引擎库
// Animation - 动画
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：应用层(4)
// 用于保存项目的动画
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-12

#include "animation.h"
#include <game/animation/avatar.h>
#include <game/config/config_manager.h>
#include <game/resource/assimp_printer.h>
#include <graphics/imath.h>
#include <klog.h>

using namespace DirectX;

namespace ifire::game {

Animation::Animation(Assets* manager, const ikit::XmlNode& node)
    : Resource(manager, node("Name"))
    , avatar_(node("Avatar"))
    , is_root_motion_(node("IsRootMotion"))
    , convert_units_(node("ConvertUnits"))
    , path_(node("Path"))
    , convert_left_hand_(node("LeftHand", true))
    , is_humanoid_(node("IsHumanoid"))
    , scale_factor_(node("ScaleFactor", 1.0f))
    , root_motion_axis_(ParseIAxis(node("RootMotionAxis"), IAxis::Z)) {
  // 处理FlipRotation
  IVec3 flip_rot = node("FlipRotation");
  is_filp_rotation = imath::IsNotZero(flip_rot);
  if (is_filp_rotation) {
    auto q = imath::EulerToQuaternion(XMLoadFloat3(&flip_rot));
    flip_rotation = XMMatrixRotationQuaternion(q);
  } else {
    flip_rotation = ID_MAT;
  }

  // 进行convert_units和scale_factor_的计算。scale_factor_会覆盖convert_units_。
  if (scale_factor_ == 1.0f && convert_units_) {
    scale_factor_ = 0.01f;
  }

  // 初始化Clips
  clips.reserve(1 + node.GetCount("Clip"));
  // 无论如何，至少有一个Master动画节点
  auto master_clip = std::make_unique<AnimationClip>(this, "Default");
  clips.push_back(std::move(master_clip));

  // 载入指定的Clip
  node.Foreach("Clip", [this](ikit::XmlNode& n, int) {
    auto sub_clip = std::make_unique<AnimationClip>(this, n);
    clips.push_back(std::move(sub_clip));
  });

  // 载入事件
  node.Foreach("Event", [this](ikit::XmlNode& n, int idx) {
    auto event = AnimationEvent(n, idx);
    auto clip = FindMasterClip(event.clip);
    clip->events.push_back(event);
  });
}

void Animation::Load() {
  // 这个首先设置，无论是否成功，都会标记已经载入
  SetLoaded();

  auto file_name = ikit::get_chars_to_gbk(name);

  Assimp::Importer importer;
  // 移除网格、材质、光照等数据，仅保留动画
  importer.SetPropertyInteger(AI_CONFIG_PP_RVC_FLAGS,
      aiComponent_MATERIALS | aiComponent_LIGHTS | aiComponent_CAMERAS);
  // 设置一个是否需要转化的标志
  int flag = aiProcess_ValidateDataStructure | aiProcess_OptimizeGraph;
  if (convert_left_hand_) {
    flag = aiProcess_ConvertToLeftHanded;
  }
  auto scene_ = importer.ReadFile(path_.c_str(), flag);

  // 载入
  if (!scene_) {
    const char* err = importer.GetErrorString();
    KERROR("ERROR::ASSIMP:: %s",
        err ? err : "Unknown error (possible file not found)");
    return;
  }

  // 将骨骼保存为自已的格式
  ikit::reset_tab();
  // armature_ = std::make_unique<Armature>(scene_);

  if (scene_->mNumAnimations == 0) {
    KERROR("%s do not have animations!", file_name.c_str());
  }

  // 将动画保存为自已的格式
  for (size_t i = 0; i < scene_->mNumAnimations; i++) {
    auto anim = scene_->mAnimations[i];
    // 如果处于Index的第一位，那么直接使用Master进行载入
    if (i == 0) {
      First()->Read(anim);
    } else {
      // 新建一个Master节点，并进行载入
      auto master_clip =
          std::make_unique<AnimationClip>(this, anim->mName.C_Str());
      master_clip->Read(anim);
      clips.push_back(std::move(master_clip));
    }
  }

  // 已经载入Master动画之后，对手动载入的动画进行配置
  for (auto& e : clips) {
    if (e->IsMaster() == false) {
      // 如果指定了名称，则查找名称（这在Find函数中已经有判断，如果没有名称，则返回Master）
      auto master_clip = FindMasterClip(e->master_name);
      // 对Clip进行设置
      e->SetMaster(master_clip);
    }
  }
}

void Animation::Ready() {
  if (!is_loaded) {
    Load();
  }
}

void Animation::Setup() {
  avatar_.set(ConfigManager::GetInstance().GetAvatar(avatar_.name));
}

AnimationClip* Animation::FindClip(ikit::sstr name) const {
  if (name.empty()) {
    return nullptr;
  }
  for (auto& e : clips) {
    if (e->name == name) {
      return e.get();
    }
  }
  return nullptr;
}

AnimationClip* Animation::First() const {
  if (clips.size() == 0) {
    return nullptr;
  }
  return clips[0].get();
}

const Avatar* Animation::GetAvatar() const { return avatar_.get(); }

AnimationClip* Animation::FindMasterClip(ikit::sstr name) const {
  // 如果没有指定名称，则返回第一个
  if (name.empty()) return First();

  for (auto& e : clips) {
    if (e->IsMaster() && e->name == name) {
      return e.get();
    }
  }

  // 没有指定的Clip，同样返回第一个
  return First();
}

} // namespace ifire::game